﻿using System;
using FunctionalCLR.Core;

namespace Zove.Runtime.InferencingStrategy
{
    public class BasicInferencingStrategy : IInferencingStrategy
    {
        private Instance sln = null;

        public BasicInferencingStrategy()
        {
        }

        #region IInferenceStrategy Members

        public int Priority()
        {
            return 0;
        }

        public void Infer(Instance sln)
        {
            this.sln = sln;

            bool eligible = false;
            bool updated = false;
            RuntimeFactor solved = null;
            RuntimeRule rr = null;

            do
            {
                updated = false;
                foreach (RuntimeEquation re in sln.Model.Equations)
                {
                    eligible = false;
                    foreach (RuntimeFactor e in re.Factors)
                    {
                        if (e.Status != RuntimeFactorStatus.Unknown)
                        {
                            continue;
                        }
                        
                        rr = sln.Model.GetRuntimeRule(re, e);
                        if (eligible == false && rr.Root != null)
                        {
                            solved = e;
                            eligible = true;
                        }
                        else
                        {
                            eligible = false;
                            break;
                        }
                    }
                    if(eligible)
                    {
                        updated = true;

                        solved.Status = RuntimeFactorStatus.Solved;
                        solved.SolvedRule = rr;

                        SolvedFactor se = new SolvedFactor();
                        se.Strategy = this;
                        se.Factor = solved;
                        se.Rule = rr;

                        this.Evaluate(se);
                        sln.Queue[solved.Name] = se;
                    }
                }
            }
            while (updated);
        }

        /// <summary>
        /// evaluate an expression
        /// </summary>
        /// <param name="expr"></param>
        /// <returns></returns>
        public double Evaluate(SolvedFactor sf)
        {
            object obj;

            try {
                obj = sf.Rule.Root.Evaluate();
                sf.Factor.Value = Convert.ToDouble(obj);
            } catch (DivideByZeroException ex) {
                Utils.Debugging(ex);
                return 0;
            }

            return sf.Factor.Value;
        }
        #endregion
    }
}
